<!--
 * @Author: wellington wellington@kreditme.id
 * @Date: 2023-07-13 16:46:50
 * @LastEditors: wellington wellington@kreditme.id
 * @LastEditTime: 2023-11-09 14:13:53
 * @FilePath: /background-removal/src/views/textArea.vue
 * @Description: 自适应文本
-->
<template>
     <div style="text-align: left;">
        <div class="container">
        
                <div class="markdown">
                    <div class="markdown-body" v-html="htmlContent"  ref="contentRef"></div>
                    <div v-show="showCursor" class="cursor"></div>
                </div>
        </div>
        <textarea @input="handleChange" class="textarea" row="1"></textarea>
    </div>
</template>

<script setup>
import {marked} from 'marked';
import "github-markdown-css/github-markdown-dark.css" // 代码块颜色，作用范围在样式名：markdown-body下的code
import hljs from 'highlight.js'
import 'highlight.js/styles/dark.css'

const render = new marked.Renderer()

marked.setOptions({
    renderer: render,
    highlight: (code, lang) => {
       
        if (lang && hljs.getLanguage(lang)) {
            return hljs.highlight(code, {language: lang}).value
        }
        return hljs.highlight(code).value
    }
})

function handleChange(e) {
    const area = e.target
    area.style.height = 'auto'
    area.style.height = area.scrollHeight + 'px'
}

const markdown = `实现ajax有两种方式：

1. XHR
2. Fetch api

其中，**XHR**的实现方式是：

\`\`\`js

const xhr = new XMLHttpRequest();
//...
\`\`\`

而**fetch api** 的实现方式是：
\`\`\`js
fetch(options);
//...
\`\`\`

`

const content = ref('')
const showCursor = ref(true)
let index = 0;
let timerID = setInterval(() => {
    if (index >= markdown.length) {
        clearInterval(timerID)
        showCursor.value = false
        return
    }
    content.value += markdown[index++]
}, 100)
const htmlContent = computed(() => {
    const html = marked.parse(content.value) // 使用marked 转变成标签文本
    // console.log(html)
    return html
})
const contentRef = ref(null)
const pos = reactive({x:0, y:0})

// 找所有文本最后一个节点，插入光标。从后往前找
const getLastTextNode = (dom) => {
    const children = dom.childNodes

    for(let i = children.length -1;i >=0;i--) {
        const node = children[i]
        // 找最后一个文本，非空节点.这个空是marked转了以后在标签后面追加的
        if (node.nodeType === Node.TEXT_NODE && /\S/.test(node.nodeValue) ) {
            // 去掉文本后面的换行符
          node.nodeValue = node.nodeValue.replace(/\s+$/, '')
            return node
        } else if (node.nodeType === Node.ELEMENT_NODE  ) {
            //如果找到的最后一个元素节点，里面还嵌套的有文本，递归找
            const last = getLastTextNode(node)
            if (last) {
                return last
            }
        }
    }
    return null
}
const updateCursor = () => {
    const contentDom = contentRef.value
    const lastText = getLastTextNode(contentDom)
    console.log(lastText?.nodeValue)
    // 创建一个节点，用来放光标，追加到最后一个文本后面.  使用零宽字符，是看不见的，但是又存在
    // const textNode = document.createTextNode('\u200b')
    const textNode = document.createTextNode('\u200b')
    if (lastText) {
        lastText.parentElement.appendChild(textNode)
    } else {
        contentDom.appendChild(textNode)
    }
    // 容器的坐标
    const domRect = contentDom.getBoundingClientRect()
    // 创建文本框选范围
    const rang = document.createRange()
    rang.setStart(textNode, 0)
    rang.setEnd(textNode, 0)
    // 再拿到坐标，相对于视口的坐标，减去容器的坐标，得到的xy就是absolute 要的坐标
    const rect = rang.getBoundingClientRect()
    pos.x = rect.left - domRect.left
    pos.y = rect.top - domRect.top
}
onMounted(updateCursor) // 首次加载光标要显示最新位置
onUpdated(updateCursor) // 每次内容更新，光标更新位置

</script>

<style  scoped>
.markdown-body {
    background: inherit;
    line-height: 2;
    padding: 0 20%;
}
.textarea {
    border: 2px solid;
    outline: none;
    width: 100%;
    line-height: 2;
    background: transparent;
    display: block;

}
.container {
    position: relative;
    width: 80%;
    margin: auto;
   
}
.markdown {
    background-color: #999;
}
.cursor {
    content: '';
    position: absolute;
    width: 10px;
    height: 16px;
    background-color: #d5d9da;
    animation: toggle 0.6s infinite;
    opacity: 0;
    transform: rotateY(3px);
    left: calc(v-bind('pos.x') * 1px);
    top: calc(v-bind('pos.y') * 1px);
}

@keyframes toggle {
    30% {
        opacity: 1;
    }
}


/* 这里备注一个闪烁光标的另一个实现 */
/* <i class="cursor-blink">&nbsp;</i> */
.cursor-blink {
  display: inline-block;
  width: 1px;
  animation: blink 1s infinite steps(1, start);
}
@keyframes blink {
  0%, 100% {
    background-color: #000;
    color: #aaa;
  }
  50% {
    background-color: #bbb; /* not #aaa because it's seem there is Google Chrome bug */
    color: #000;
  }
}
</style>